
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */ 
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

#include "RTVector4f.h"


#include <math.h>

namespace RT
{

	//empty constructor, set all values to 0
	RTVector4f::RTVector4f()
	{
		_xyzw[0] = _xyzw[1] = _xyzw[2] = _xyzw[3] = 0;
	}

	//constructor : set the values to the parameter's value
	RTVector4f::RTVector4f(F32 x, F32 y, F32 z, F32 w)
	{
		RTVEC4X = x;
		RTVEC4Y = y;
		RTVEC4Z = z;
		RTVEC4W = w;
	}

	//constructor from a Vector3f
	RTVector4f::RTVector4f(const RTVector3f& v, F32 w)
	{
		RTVEC4X = v.x;
		RTVEC4Y = v.y;
		RTVEC4Z = v.z;
		RTVEC4W = w;
	}

	//destructor
	RTVector4f::~RTVector4f(){}

	//add two vectors and return the result
	RTVector4f RTVector4f::operator +(const RTVector4f& v)const
	{
		RTVector4f res;
		res.RTVEC4X = v.RTVEC4X + RTVEC4X;
		res.RTVEC4Y = v.RTVEC4Y + RTVEC4Y;
		res.RTVEC4Z = v.RTVEC4Z + RTVEC4Z;
		res.RTVEC4W = v.RTVEC4W + RTVEC4W;

		return res;
	}

	//substract two vectors and return the result
	RTVector4f RTVector4f::operator -(const RTVector4f& v)const
	{
		RTVector4f res;
		res.RTVEC4X = RTVEC4X - v.RTVEC4X;
		res.RTVEC4Y = RTVEC4Y - v.RTVEC4Y;
		res.RTVEC4Z = RTVEC4Z - v.RTVEC4Z;
		res.RTVEC4W = RTVEC4W - v.RTVEC4W;

		return res;
	}

	//unary substract operation
	RTVector4f RTVector4f::operator -()const
	{
		RTVector4f res;
		res.RTVEC4X = -RTVEC4X;
		res.RTVEC4Y = -RTVEC4Y;
		res.RTVEC4Z = -RTVEC4Z;
		res.RTVEC4W = -RTVEC4W;

		return res;
	}

	//multiply with a F32 and return the result
	RTVector4f RTVector4f::operator *(F32 a)const
	{
		RTVector4f res;
		res.RTVEC4X = RTVEC4X * a;
		res.RTVEC4Y = RTVEC4Y * a;
		res.RTVEC4Z = RTVEC4Z * a;
		res.RTVEC4W = RTVEC4W * a;

		return res;
	}

	//multiply two vectors and return the result
	RTVector4f RTVector4f::operator *(const RTVector4f& v)const
	{
		RTVector4f res;
		res.RTVEC4X = RTVEC4X * v.RTVEC4X;
		res.RTVEC4Y = RTVEC4Y * v.RTVEC4Y;
		res.RTVEC4Z = RTVEC4Z * v.RTVEC4Z;
		res.RTVEC4W = RTVEC4W * v.RTVEC4W;

		return res;
	}

	//multiply a vector by a matrix
	RTVector4f RTVector4f::operator*(const RTMatrix44& m)const
	{
		RTVector4f res;

		res.RTVEC4X = RTVEC4X * m.m_array[0][0] + RTVEC4Y * m.m_array[1][0] + RTVEC4Z * m.m_array[2][0] + RTVEC4W * m.m_array[3][0];
		res.RTVEC4Y = RTVEC4X * m.m_array[0][1] + RTVEC4Y * m.m_array[1][1] + RTVEC4Z * m.m_array[2][1] + RTVEC4W * m.m_array[3][1];
		res.RTVEC4Z = RTVEC4X * m.m_array[0][2] + RTVEC4Y * m.m_array[1][2] + RTVEC4Z * m.m_array[2][2] + RTVEC4W * m.m_array[3][2];
		res.RTVEC4W = RTVEC4X * m.m_array[0][3] + RTVEC4Y * m.m_array[1][3] + RTVEC4Z * m.m_array[2][3] + RTVEC4W * m.m_array[3][3];

		return res;
	}

	//divide with a F32 and return the result
	RTVector4f RTVector4f::operator /(F32 a)const
	{
		F32 op = 1.f/a;

		RTVector4f res;
		res.RTVEC4X = RTVEC4X * op;
		res.RTVEC4Y = RTVEC4Y * op;
		res.RTVEC4Z = RTVEC4Z * op;
		res.RTVEC4W = RTVEC4W * op;

		return res;
	}

	//add the parameter and store the result
	void RTVector4f::operator += (const RTVector4f& v)
	{
		RTVEC4X += v.RTVEC4X;
		RTVEC4Y += v.RTVEC4Y;
		RTVEC4Z += v.RTVEC4Z;
		RTVEC4W += v.RTVEC4W;
	}

	//add the parameter and store the result
	void RTVector4f::operator += (const RTVector3f& v)
	{
		RTVEC4X += v.x;
		RTVEC4Y += v.y;
		RTVEC4Z += v.z;
	}

	//multiply with the parameter and store the result
	void RTVector4f::operator *= (F32 f)
	{
		RTVEC4X *= f;
		RTVEC4Y *= f;
		RTVEC4Z *= f;
		RTVEC4W *= f;
	}

	//equality test. Return true if the two vectors are equals. Return false if the vectors have different values.
	bool RTVector4f::operator == (const RTVector4f& v)
	{
		if (RTVEC4X != v.RTVEC4X || RTVEC4Y != v.RTVEC4Y || RTVEC4Z != v.RTVEC4Z || RTVEC4W != v.RTVEC4W)
			return false;

		return true;
	}

	//Return true if the two vectors are different and false if there are equals
	bool RTVector4f::operator != (const RTVector4f& v)
	{
		if (RTVEC4X != v.RTVEC4X || RTVEC4Y != v.RTVEC4Y || RTVEC4Z != v.RTVEC4Z || RTVEC4W != v.RTVEC4W)
			return true;

		return false;
	}

	//calculate a dot product (the fourth parameter is ignored)
	F32 RTVector4f::dot(const RTVector4f& v)const
	{
		return RTVEC4X*v.RTVEC4X + RTVEC4Y*v.RTVEC4Y + RTVEC4Z*v.RTVEC4Z;
	}

	//calculate a cross product (the fourth parameter is ignored)
	RTVector4f RTVector4f::cross(const RTVector4f& v)const
	{
		RTVector4f res;

		res.RTVEC4X = RTVEC4Y*v.RTVEC4Z - RTVEC4Z*v.RTVEC4Y;
		res.RTVEC4Y = RTVEC4Z*v.RTVEC4X - RTVEC4X*v.RTVEC4Z;
		res.RTVEC4Z = RTVEC4X*v.RTVEC4Y - RTVEC4Y*v.RTVEC4X;
		res.RTVEC4W = 1;

		return res;
	}

	//calculate the vector's norme
	F32 RTVector4f::norme()const
	{
		F32 n2 = norme2();

		return sqrt(n2);
	}

	//calculate the vector's square norme
	F32 RTVector4f::norme2()const
	{
		return RTVEC4X*RTVEC4X + RTVEC4Y*RTVEC4Y + RTVEC4Z*RTVEC4Z;
	}

	//normalize the vector
	void RTVector4f::normalize()
	{
		F32 n = 1.f/norme();

		RTVEC4X *= n;
		RTVEC4Y *= n;
		RTVEC4Z *= n;
		RTVEC4W *= n;
	}

	//saturate the vector between 0 and 1
	void RTVector4f::saturate()
	{
		if(RTVEC4X<0) RTVEC4X = 0;
		else if(RTVEC4X>1) RTVEC4X = 1;

		if(RTVEC4Y<0) RTVEC4Y = 0;
		else if(RTVEC4Y>1) RTVEC4Y = 1;

		if(RTVEC4Z<0) RTVEC4Z = 0;
		else if(RTVEC4Z>1) RTVEC4Z = 1;

		if(RTVEC4W<0) RTVEC4W = 0;
		else if(RTVEC4W>1) RTVEC4W = 1;
	}

	//set the vector to the distance given as parameter. The vector gotta be normalized.
	void RTVector4f::maximize(F32 max)
	{
		RTVEC4X *= max;
		RTVEC4Y *= max;
		RTVEC4Z *= max;
		RTVEC4W *= max;
	}

	//conversion operator to RTVector3f
	RTVector4f::operator RTVector3f()
	{
		return RTVector3f(RTVEC4X, RTVEC4Y, RTVEC4Z);
	}

}